package com.xxtx.trade.common.util;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class IdCreateUtil {
    private static final long twepoch = 1288834974657L;
    private static final long workerIdBits = 5L;
    private static final long datacenterIdBits = 5L;
    private static final long maxWorkerId = 31L;
    private static final long maxDatacenterId = 31L;
    private static final long sequenceBits = 12L;
    private static final long workerIdShift = 12L;
    private static final long datacenterIdShift = 17L;
    private static final long timestampLeftShift = 22L;
    private static final long sequenceMask = 4095L;
    private static long lastTimestamp = -1L;
    private long sequence = 0L;
    private final long workerId;
    private final long datacenterId;
    private static IdCreateUtil idWorker = new IdCreateUtil(31L, 31L);

    private static int userNumber = 200;
    private static CountDownLatch countDownLatch = new CountDownLatch(userNumber);
    public IdCreateUtil() {
        this.datacenterId = getDatacenterId(31L);
        this.workerId = getMaxWorkerId(this.datacenterId, 31L);
    }

    public IdCreateUtil(Long workerId, long datacenterId) {
        if (workerId <= 31L && workerId >= 0L) {
            if (datacenterId <= 31L && datacenterId >= 0L) {
                this.workerId = workerId;
                this.datacenterId = datacenterId;
            } else {
                throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", 31L));
            }
        } else {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", 31L));
        }
    }

    public synchronized long nextId() {
        long timestamp = this.timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        } else {
            if (lastTimestamp == timestamp) {
                this.sequence = this.sequence + 1L & 4095L;
                if (this.sequence == 0L) {
                    timestamp = this.tilNextMillis(lastTimestamp);
                }
            } else {
                this.sequence = 0L;
            }

            lastTimestamp = timestamp;
            long nextId = timestamp - 1288834974657L << 22 | this.datacenterId << 17 | this.workerId << 12 | this.sequence;
            return nextId;
        }
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp;
        for(timestamp = this.timeGen(); timestamp <= lastTimestamp; timestamp = this.timeGen()) {
            ;
        }

        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    protected static long getMaxWorkerId(Long datacenterId, long maxWorkerId) {
        StringBuffer mpid = new StringBuffer();
        mpid.append(datacenterId);
        String name = ManagementFactory.getRuntimeMXBean().getName();
        if (!name.isEmpty()) {
            mpid.append(name.split("@")[0]);
        }

        return (long)(mpid.toString().hashCode() & '\uffff') % (maxWorkerId + 1L);
    }

    protected static long getDatacenterId(long maxDatacenterId) {
        long id = 0L;

        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            if (network == null) {
                id = 1L;
            } else {
                byte[] mac = network.getHardwareAddress();
                id = (255L & (long)mac[mac.length - 1] | 65280L & (long)mac[mac.length - 2] << 8) >> 6;
                id %= maxDatacenterId + 1L;
            }
        } catch (Exception var7) {
            System.out.println(" getDatacenterId: " + var7.getMessage());
        }

        return id;
    }

//    public static long getId() {
//        try {
//            String id = String.valueOf(idWorker.nextId());
//            Thread.sleep(1);
//            return Long.valueOf(id.substring(0, 15));
//        }catch (Exception e){
//            return 0L;
//        }
//    }

    public static String getId() {
        try {
            String id = String.valueOf(idWorker.nextId());
            Thread.sleep(1);
            return id;
        }catch (Exception e){
            return "";
        }
    }

    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {

        CyclicBarrier cy = new CyclicBarrier(userNumber + 1);

        long start = System.currentTimeMillis();
        //测试并发条件下生成订单号
        for(int i=0;i < userNumber;i++){
            new Thread("线程:"+ (i+1)){
                @Override
                public void run() {
                    try {
                        countDownLatch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ " " + IdCreateUtil.getId());
                    try {
                        cy.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            countDownLatch.countDown();
        }
        cy.await();
        long end = System.currentTimeMillis() - start;

        System.out.println("总耗时"+ end + " ms");
//        long startTime = System.currentTimeMillis();
//        System.out.println(getId());
//        Map m = new HashMap();
//
//        for(int i = 0; i < 100000; ++i) {
//            IdCreateUtil var10000 = idWorker;
//            long id = getId();
//            if (id == 9007199254740992L) {
//                throw new RuntimeException("》》javascript最大允许值");
//            }
//
//            String sid = String.valueOf(id);
//            System.out.println(sid);
//            if (m.containsKey(sid)) {
//                throw new RuntimeException("出错");
//            }
//
//            m.put(sid, 0);
//            if (sid.length() > 18) {
//                throw new RuntimeException("出错");
//            }
//        }
//
//        System.out.println("finishz(ms):" + (System.currentTimeMillis() - startTime) / 1000L);
    }
}
